﻿using System;
using System.Collections.Generic;
// ReSharper disable RedundantUsingDirective
using System.Deployment.Application;
// ReSharper restore RedundantUsingDirective
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows.Forms;

using Microsoft.Win32;

using QuickTuner.Properties;
using QuickTuner.RadioProtocol;
using QuickTuner.Util;

namespace QuickTuner
{
    internal static class Program
    {
        internal static Settings Config;

        internal static Radio TheRadio;
        internal static radioForm MainForm;

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        private static void Main()
        {
            // for resetting in dev environment, execute:
            // Storage.LoadDefaultTemplates();

            // visual themes support, required to run first thing
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            
#if DEBUG
            // always run configure radio protocol when debugging
            configureRadioProtocol();

#else
            // if first-time, setup the radio protocol
            if (ApplicationDeployment.IsNetworkDeployed)
                if (ApplicationDeployment.CurrentDeployment.IsFirstRun)
                    configureRadioProtocol();

#endif


            // on first instance, call createMainForm to create the main form and run it
            var controller = new InstanceController(createMainForm, true);

            // on second instance, assume a radio:// protocol has been passed
            // thus invoking the processCommandLine method instead
            controller.StartupNextInstance += (sender, e) => processCommandLine(e.CommandLine);

            // cleanup 
            controller.Shutdown += (sender, e) => shutdown();

            // spin the main loop
            controller.Run(Environment.GetCommandLineArgs());
        }

        /// <summary>
        /// Verify, initialize and update the radio:// protocol support
        /// to use the most recent QuickTuner exe
        /// </summary>
        private static void configureRadioProtocol()
        {
            var r = Registry.ClassesRoot.OpenSubKey("radio");

            // the base radio key exists?
            if (r == null)
                goto install;

            // verify the base radio key
            if (string.IsNullOrEmpty(r.GetValue(null) as string) || r.GetValue("URL Protocol") == null)
                goto install;

            // lambdarians are here
            Func<string, bool> check = key => (r = r.OpenSubKey(key)) != null;

            // verify the subsequent shell/open/command key
            if (check("shell") && check("open") && check("command"))
            {
                // check the "command" key value
                var curHandler = r.GetValue(null) as string;
                var curExe = Application.ExecutablePath;

                if (!string.IsNullOrEmpty(curHandler) && !curHandler.StartsWith(curExe))
                    goto install;
            }
            else
                goto install;

            return;

            install:

            // ask the user first wether its ok to install something into the registry
            var confirm = MessageBox.Show(
                "QuickTuner will now try to install support for radio:// URLs.\n\n" +
                    "Please click OK and then YES to proceed, otherwise click Cancel.",
                "QuickTuner",
                MessageBoxButtons.OKCancel);

            // if user's ok, proceed with install
            if (confirm == DialogResult.OK)
                installRadioProtocol();
        }

        /// <summary>
        /// Attemp to install the radio protocol and this EXE as the protocol handler
        /// </summary>
        private static void installRadioProtocol()
        {
            // fetch the templated registry file
            var radioReg = Resources.radio_protocol_reg;

            // fill in the template blanks
            var exe = Application.ExecutablePath;
            radioReg = string.Format(radioReg, exe.RegistryEscape());

            // execute the file to add registry content to user machine
            // this is required to be run externally due to UAC and ClickOnce limitations

            var tempFilename = Path.ChangeExtension(Path.GetTempFileName(), ".reg");
            File.WriteAllText(tempFilename, radioReg);

            var p = Process.Start(tempFilename);
            if (p == null) return;

            p.WaitForExit();
            p.Dispose();

            File.Delete(tempFilename);
        }

        /// <summary>
        /// Creates the main QuickTuner form and related supports.
        /// </summary>
        public static Form createMainForm() {

            // load the saved settings, not the default values
            Config = Settings.Default;

            // load radio from storage
            var radio = Storage.LoadRadio();
            radio.PlayEngine = new IEPlayEngine();

            TheRadio = radio;

            // create main form
            MainForm = new radioForm(radio);

            return MainForm;
        }

        /// <summary>
        /// Process command line passed from a new instance.
        /// Which is the case when the radio:// protocol was activated.
        /// </summary>
        private static void processCommandLine(IEnumerable<string> cmdLineArgs)
        {
            var radio = TheRadio;
            var form = MainForm;

            // skip the first arg, which is the exe path
            cmdLineArgs = cmdLineArgs.Skip(1);

            // does nothing if no radio instance exists
            if (radio == null) return;

            // parse the actions passed in
            var parser = new ProtocolParser();
            var actions = cmdLineArgs.Select(arg => parser.Parse(arg));

            // filter out and execute all executable action
            actions = actions.Where(act => act.CanExecute(radio));
            actions.ForEach(act => act.Execute(radio));

            // reflect changes on main form
            form.RefreshRadioState();
        }

        /// <summary>
        /// Save setings and cleanup resources
        /// </summary>
        public static void shutdown()
        {

            if (TheRadio == null) return;

            Storage.SaveRadio(TheRadio);
            Config.Save();
        }
    }
}